package com.ahdy.tool;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 音频处理工具类
 * 用于音频格式检测、转换和预处理
 *
 * @author ahdy
 * @since 1.0.0
 */
@Slf4j
@Component
public class AudioProcessor {

    // 音频格式魔数
    private static final Map<String, byte[]> AUDIO_MAGIC_NUMBERS = new HashMap<>();

    static {
        // WAV格式: RIFF + 4字节长度 + WAVE
        AUDIO_MAGIC_NUMBERS.put("wav", new byte[] { 'R', 'I', 'F', 'F' });

        // MP3格式: ID3v2 或 MPEG帧头
        AUDIO_MAGIC_NUMBERS.put("mp3", new byte[] { (byte) 0xFF, (byte) 0xE0 });

        // FLAC格式: fLaC
        AUDIO_MAGIC_NUMBERS.put("flac", new byte[] { 'f', 'L', 'a', 'C' });

        // M4A格式: ftyp
        AUDIO_MAGIC_NUMBERS.put("m4a", new byte[] { 'f', 't', 'y', 'p' });

        // AAC格式: ADIF头
        AUDIO_MAGIC_NUMBERS.put("aac", new byte[] { 'A', 'D', 'I', 'F' });

        // AMR格式: #!AMR
        AUDIO_MAGIC_NUMBERS.put("amr", new byte[] { '#', '!', 'A', 'M', 'R' });
    }

    /**
     * 检测音频格式
     *
     * @param audioData 音频数据
     * @return 检测到的格式，如果无法识别返回 "unknown"
     */
    public String detectAudioFormat(byte[] audioData) {
        if (audioData == null || audioData.length < 12) {
            return "unknown";
        }

        // 检查WAV格式
        if (isWavFormat(audioData)) {
            return "wav";
        }

        // 检查MP3格式
        if (isMp3Format(audioData)) {
            return "mp3";
        }

        // 检查FLAC格式
        if (isFlacFormat(audioData)) {
            return "flac";
        }

        // 检查M4A格式
        if (isM4aFormat(audioData)) {
            return "m4a";
        }

        // 检查AAC格式
        if (isAacFormat(audioData)) {
            return "aac";
        }

        // 检查AMR格式
        if (isAmrFormat(audioData)) {
            return "amr";
        }

        return "unknown";
    }

    /**
     * 检查是否为WAV格式
     */
    private boolean isWavFormat(byte[] data) {
        return data[0] == 'R' && data[1] == 'I' && data[2] == 'F' && data[3] == 'F' &&
                data[8] == 'W' && data[9] == 'A' && data[10] == 'V' && data[11] == 'E';
    }

    /**
     * 检查是否为MP3格式
     */
    private boolean isMp3Format(byte[] data) {
        // 检查ID3v2标签
        if (data[0] == 'I' && data[1] == 'D' && data[2] == '3') {
            return true;
        }

        // 检查MPEG帧头
        if ((data[0] & 0xFF) == 0xFF && (data[1] & 0xE0) == 0xE0) {
            return true;
        }

        return false;
    }

    /**
     * 检查是否为FLAC格式
     */
    private boolean isFlacFormat(byte[] data) {
        return data[0] == 'f' && data[1] == 'L' && data[2] == 'a' && data[3] == 'C';
    }

    /**
     * 检查是否为M4A格式
     */
    private boolean isM4aFormat(byte[] data) {
        // M4A文件通常在偏移4字节处有ftyp
        return data[4] == 'f' && data[5] == 't' && data[6] == 'y' && data[7] == 'p';
    }

    /**
     * 检查是否为AAC格式
     */
    private boolean isAacFormat(byte[] data) {
        // 检查ADIF头
        if (data[0] == 'A' && data[1] == 'D' && data[2] == 'I' && data[3] == 'F') {
            return true;
        }

        // 检查ADTS头
        if ((data[0] & 0xFF) == 0xFF && (data[1] & 0xF0) == 0xF0) {
            return true;
        }

        return false;
    }

    /**
     * 检查是否为AMR格式
     */
    private boolean isAmrFormat(byte[] data) {
        return data[0] == '#' && data[1] == '!' && data[2] == 'A' &&
                data[3] == 'M' && data[4] == 'R';
    }

    /**
     * 获取音频基本信息
     *
     * @param audioData 音频数据
     * @return 音频信息
     */
    public Map<String, Object> getAudioInfo(byte[] audioData) {
        Map<String, Object> info = new HashMap<>();

        String format = detectAudioFormat(audioData);
        info.put("format", format);
        info.put("size", audioData.length);
        info.put("sizeInMB", String.format("%.2f", audioData.length / 1024.0 / 1024.0));

        // 根据格式获取更多信息
        switch (format) {
            case "wav":
                info.putAll(getWavInfo(audioData));
                break;
            case "mp3":
                info.putAll(getMp3Info(audioData));
                break;
            case "flac":
                info.putAll(getFlacInfo(audioData));
                break;
            default:
                info.put("supported", false);
                info.put("message", "格式暂不支持详细信息获取");
        }

        return info;
    }

    /**
     * 获取WAV文件信息
     */
    private Map<String, Object> getWavInfo(byte[] data) {
        Map<String, Object> info = new HashMap<>();
        try {
            // 读取采样率 (偏移24-27字节)
            int sampleRate = (data[27] & 0xFF) << 24 | (data[26] & 0xFF) << 16 |
                    (data[25] & 0xFF) << 8 | (data[24] & 0xFF);

            // 读取声道数 (偏移22-23字节)
            int channels = (data[23] & 0xFF) << 8 | (data[22] & 0xFF);

            // 读取位深度 (偏移34-35字节)
            int bitsPerSample = (data[35] & 0xFF) << 8 | (data[34] & 0xFF);

            info.put("sampleRate", sampleRate);
            info.put("channels", channels);
            info.put("bitsPerSample", bitsPerSample);
            info.put("supported", true);

        } catch (Exception e) {
            log.warn("解析WAV文件信息失败", e);
            info.put("supported", false);
            info.put("error", e.getMessage());
        }
        return info;
    }

    /**
     * 获取MP3文件信息
     */
    private Map<String, Object> getMp3Info(byte[] data) {
        Map<String, Object> info = new HashMap<>();
        try {
            // 查找MPEG帧头
            int frameHeaderOffset = findMpegFrameHeader(data);
            if (frameHeaderOffset >= 0) {
                int frameHeader = (data[frameHeaderOffset] & 0xFF) << 24 |
                        (data[frameHeaderOffset + 1] & 0xFF) << 16 |
                        (data[frameHeaderOffset + 2] & 0xFF) << 8 |
                        (data[frameHeaderOffset + 3] & 0xFF);

                // 解析采样率
                int sampleRateIndex = (frameHeader >> 10) & 0x3;
                int sampleRate = getMp3SampleRate(sampleRateIndex);

                // 解析声道模式
                int channelMode = (frameHeader >> 6) & 0x3;

                info.put("sampleRate", sampleRate);
                info.put("channelMode", channelMode);
                info.put("supported", true);
            } else {
                info.put("supported", false);
                info.put("error", "未找到MPEG帧头");
            }

        } catch (Exception e) {
            log.warn("解析MP3文件信息失败", e);
            info.put("supported", false);
            info.put("error", e.getMessage());
        }
        return info;
    }

    /**
     * 获取FLAC文件信息
     */
    private Map<String, Object> getFlacInfo(byte[] data) {
        Map<String, Object> info = new HashMap<>();
        try {
            // FLAC文件头信息在偏移4字节后
            if (data.length > 20) {
                // 读取采样率 (偏移18-21字节)
                int sampleRate = (data[21] & 0xFF) << 24 | (data[20] & 0xFF) << 16 |
                        (data[19] & 0xFF) << 8 | (data[18] & 0xFF);

                // 读取声道数 (偏移17字节)
                int channels = (data[17] & 0x7) + 1;

                // 读取位深度 (偏移22字节)
                int bitsPerSample = ((data[22] & 0x1E) >> 1) + 1;

                info.put("sampleRate", sampleRate);
                info.put("channels", channels);
                info.put("bitsPerSample", bitsPerSample);
                info.put("supported", true);
            } else {
                info.put("supported", false);
                info.put("error", "文件太小，无法解析FLAC信息");
            }

        } catch (Exception e) {
            log.warn("解析FLAC文件信息失败", e);
            info.put("supported", false);
            info.put("error", e.getMessage());
        }
        return info;
    }

    /**
     * 查找MPEG帧头
     */
    private int findMpegFrameHeader(byte[] data) {
        for (int i = 0; i < data.length - 4; i++) {
            if ((data[i] & 0xFF) == 0xFF && (data[i + 1] & 0xE0) == 0xE0) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 获取MP3采样率
     */
    private int getMp3SampleRate(int index) {
        int[] sampleRates = { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000 };
        return index < sampleRates.length ? sampleRates[index] : 0;
    }

    /**
     * 检查音频是否适合ASR处理
     *
     * @param audioData 音频数据
     * @return 检查结果
     */
    public Map<String, Object> checkAsrCompatibility(byte[] audioData) {
        Map<String, Object> result = new HashMap<>();
        Map<String, Object> audioInfo = getAudioInfo(audioData);

        String format = (String) audioInfo.get("format");
        boolean supported = !"unknown".equals(format);

        result.put("compatible", supported);
        result.put("format", format);
        result.put("audioInfo", audioInfo);

        if (supported) {
            result.put("message", "音频格式支持ASR处理");

            // 检查采样率
            Integer sampleRate = (Integer) audioInfo.get("sampleRate");
            if (sampleRate != null) {
                if (sampleRate == 16000) {
                    result.put("sampleRateCompatible", true);
                    result.put("sampleRateMessage", "采样率适合ASR处理");
                } else {
                    result.put("sampleRateCompatible", false);
                    result.put("sampleRateMessage", "建议转换为16kHz采样率以获得最佳识别效果");
                }
            }
        } else {
            result.put("message", "音频格式不支持ASR处理");
        }

        return result;
    }

    /**
     * 获取支持的音频格式列表
     */
    public String[] getSupportedFormats() {
        return AUDIO_MAGIC_NUMBERS.keySet().toArray(new String[0]);
    }
}
